package concurrent.thread;

import cn.hutool.core.util.StrUtil;
import com.alibaba.cloudapi.sdk.client.OkHttp3Client;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @program JavaBase
 * @description: 线程通知与等待
 * @author: zhanglu
 * @create: 2021-04-29 15:03:00
 */
@Slf4j
public class NotifyWait {

    /**
     * wait()：当一个线调用一个共享变量的wait()方法时，该调用线程会被阻塞挂起。
     *  - 其他线程调用了该共享变量的notify()、notifyAll()
     *  - 其他线程调用了该线程的interrupt()方法，该线程抛出中断异常
     *  - 注意：只会释放当前对象的锁
     *
     *  监视器锁
     *  - synchronized(共享变量){}
     *
     *  notify()：随机唤醒一个等待线程
     *  notifyAll()：唤醒所有的等待线程
     */
    @Test
    public void test01() throws InterruptedException {
        Integer maxSize = 10;
        LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
        new Thread(() -> {
            while (true){
                synchronized (queue){
                    while (queue.size() == maxSize){
                        try {
                            //挂起当前线程，并释放通过同步块获取的queue上的锁，让消费者线程可以获取该锁
                            queue.wait();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer("xxx");
                    System.out.println(StrUtil.format("生产一个，总计{}个", queue.size()));
                    queue.notifyAll();
                }
            }
        }).start();
       new Thread(() -> {
           while (true){
               synchronized (queue){
                   while (queue.size() == 0){
                       try {
                           //挂起当前线程，并释放通过同步块获取的queue上的锁，让生产者线程可以获取该锁
                           queue.wait();
                       } catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
                   try {
                       queue.take();
                       System.out.println(StrUtil.format("消费一个，总计{}个", queue.size()));
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   queue.notifyAll();
               }
           }
       }).start();

       while (true){}

    }


    @Test
    public void test02() throws InterruptedException {
        Thread thread = new Thread(() -> {
            synchronized (this){
                try {
                    System.out.println("线程执行开始");
                    this.wait();
                    System.out.println("线程执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("线程执行异常");
                }
            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println("程序执行开始");
        thread.interrupt();
        System.out.println("程序执行结束");
    }

    @Test
    public void test03() throws InterruptedException {
        /*
            void interrupt()：中断线程，实际上设置线程中断标志位为true
            boolean isInterrupted()：检测当前线程是否被中断，是返回true
            boolean interrupted()：检测当前线程是否被中断，是返回true。若当前线程被中断则清除中断标志位，获取当前线程并不是调用的对象。
         */
        Thread thread = new Thread(() -> {
            while (true) {
                //log.info("" + Thread.interrupted());
            }
        });
        thread.start();
        thread.interrupt();
        log.info("" + thread.isInterrupted());
        log.info("" + thread.interrupted());
        log.info("" + Thread.interrupted());
        log.info("" + thread.isInterrupted());
        thread.join();
        log.info("main thread is over");
    }

    /**
     * 优雅退出
     */
    @Test
    public void test04() throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
            }
            log.info("子线程被中断" + Thread.interrupted());
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
        thread.join();
        log.info("main thread is over");
    }

    @Test
    public void test05() throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
            }
        });
        thread.start();
        thread.interrupt();
        System.out.println(thread.isInterrupted());
        System.out.println(thread.interrupted());
        System.out.println(Thread.interrupted());
        System.out.println(thread.isInterrupted());
        thread.join();
        System.out.println("main is over");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                log.info("...");
                if(Thread.currentThread().isInterrupted()){
                    throw new RuntimeException("中断了");
                }
            }
        });
        thread.start();
        TimeUnit.MILLISECONDS.sleep(5);
        thread.interrupt();
//        thread.join();
        log.info("main thread is over");
    }



}
